package org.hs.phd.odi.bgsub.tracking;

import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;

import org.hs.phd.odi.bgsub.features.FeatureMatcher;
import org.hs.phd.odi.bgsub.vob.VisualObject;

public class ParticleFilterVisualObjectTracker implements VisualObjectTracker {

	private static final int MAX_UNMATCHING_FRAME_COUNT = 2;
	private static final int MIN_FRAME_COUNT_FOR_TRACK_INITIATION = 3;
	
	private List<TrackedObject> trackedObjects;
	private List<TrackedObject> candidateNewTracks;
	private List<TrackedObject> disappearedOldTracks;

	
	public ParticleFilterVisualObjectTracker(){
		trackedObjects = new ArrayList<TrackedObject>();
		candidateNewTracks = new ArrayList<TrackedObject>();
		disappearedOldTracks = new ArrayList<TrackedObject>();
	}

	@Override
	public List<? extends VisualObject> track(List<VisualObject> currentFrameObjects) {
		return currentFrameObjects;
		
//		pruneObjectsWithNoFeatures(currentFrameObjects);
//		
//		ObjectListMatcher matcher = new ObjectListMatcher(featureMatcher);
//		matcher.match(trackedObjects, currentFrameObjects);
//
//		trackedObjects.clear();
//		addMatchingTracks(matcher.getMatchingTracks());
//		
//		
//		processTrackCandidates(matcher.getNewObjects());
//
//		processNonMatchingTracks(matcher.getNonMatchingTracks());
//		
//		return trackedObjects;
		
		/*
		List<TrackedObject> allTracksIncludeingCandidates = new ArrayList<TrackedObject>();
		allTracksIncludeingCandidates.addAll(trackedObjects);
		allTracksIncludeingCandidates.addAll(candidateNewTracks);
		
		return allTracksIncludeingCandidates;
		*/
		
	}

	private void pruneObjectsWithNoFeatures(List<VisualObject> currentFrameObjects) {
		for( Iterator<VisualObject> iterator = currentFrameObjects.iterator(); iterator.hasNext(); ){
			
			if(iterator.next().getFeatures() == null){
				iterator.remove();
			}
		}
	}

	private void processNonMatchingTracks(List<TrackedObject> nonMatchingTracks) {
		/*
		 * 3. check nonMatchingTracks and increment unmatchingFrameCount. 
		 * 3.1. if unmatchingFrameCount < MAX_UNMATCHING_FRAME_COUNT add to the final list
		 * 3.2 else addToOldItemsList for reidentification
		 */
		for(TrackedObject obj : nonMatchingTracks){
			obj.incrementUnmatchingFrameCount();
			
			if( !obj.isDroppable() ){
				trackedObjects.add(obj);
			}else{
				disappearedOldTracks.add(obj);
			}
		}
		
	}

	private void processTrackCandidates(List<VisualObject> newObjects) {
		 /* 
		 * 2. add newObjects as new tracks (initialize classificatioCounts, unmatchingFrameCount)
		 * 2.1 !!! Maintain a track candidates list and move the items with trackedFrameCount > MIN_TRACK_FRAME_COUNT to the track list
		 * 2.1.1 while moving candidates to track list, check if there is a match in oldItems (for reidentification), if matches associate with it
		 */
		// add new items as new tracks
		// move the items with trackedFrameCount > MIN_TRACK_FRAME_COUNT to the track list (check for reidentification here)
		// update unmatching counts, if unmatchingFrameCount > MAX_UNMATCHING_FRAME_COUNT remove from new tracks

		
//		ObjectListMatcher matcher = new ObjectListMatcher(featureMatcher);
//		matcher.match(candidateNewTracks, newObjects);
//
//		candidateNewTracks.clear();
//
//		for(Entry<TrackedObject, VisualObject> matchingTrack : matcher.getMatchingTracks().entrySet()){
//			
//			TrackedObject trackedObject = matchingTrack.getKey();
//			VisualObject currentFrameVisualObject = matchingTrack.getValue();
//			trackedObject.updateWithCurrentFrameMatch(currentFrameVisualObject);
//			
//			if(trackedObject.isStableTrack() ){
//
//				//TODO PERFORM REIDENTIFICATION
//				/*
//				TrackedObject reidentifiedOldObject = (TrackedObject) matcher.findBestMatchingTrack(trackedObject, disappearedOldTracks);
//				
//				if(reidentifiedOldObject != null){
//					trackedObject.merge(reidentifiedOldObject);
//					disappearedOldTracks.remove(reidentifiedOldObject);
//				}
//				*/
//				
//				trackedObjects.add(trackedObject);	
//			}else{
//				candidateNewTracks.add(trackedObject);
//			}
//		}
//		
//		
//		for(VisualObject obj:matcher.getNewObjects()){
//			candidateNewTracks.add(new TrackedObject(obj, MIN_FRAME_COUNT_FOR_TRACK_INITIATION, MAX_UNMATCHING_FRAME_COUNT));
//		}
//		
//
//		for(TrackedObject obj : matcher.getNonMatchingTracks()){
//			obj.incrementUnmatchingFrameCount();
//			
//			if(!obj.isDroppable() ){
//				candidateNewTracks.add(obj);
//			}
//		}
	}

	private void addMatchingTracks(IdentityHashMap<TrackedObject, VisualObject> matchingTracks) {
		for(Entry<TrackedObject, VisualObject> matchingTrack : matchingTracks.entrySet()){
			
			TrackedObject trackedObject = matchingTrack.getKey();
			VisualObject currentFrameVisualObject = matchingTrack.getValue();
			trackedObject.updateWithCurrentFrameMatch(currentFrameVisualObject);
			trackedObjects.add(trackedObject);
		}
	}

	
}
